package org.annoflow.policy;

import java.util.HashMap;
import java.util.LinkedList;

import org.annoflow.policy.boundry.InsecureClassPolicy;
import org.annoflow.util.WeakIdentityHashMap;

public class PolicyManager
{
	private static HashMap<String, PolicyType> classPolicies = null;
	private static WeakIdentityHashMap<Object, PolicyType> objectPolicies = null;
	private static HashMap<Object, LinkedList<Object>> parentMap = null;

	public static void addClassPolicy(Class<?> clazz, PolicyType policy)
	{
		//System.err.println("Adding class Policy: " + clazz.getName() + " " + policy.getClass().getName());
		if (classPolicies == null)
		{
			classPolicies = new HashMap<String, PolicyType>();
		}
		classPolicies.put(clazz.getName(), policy);
	}
	public static void addFieldPolicy(Object o, Object parent, Class<? extends PolicyType> policyClass)
	{
		if (objectPolicies == null)
		{
			objectPolicies = new WeakIdentityHashMap<Object, PolicyType>();
		}
		if (parentMap == null)
		{
			parentMap = new HashMap<Object, LinkedList<Object>>();
		}
		PolicyType policy = null;
		try {
			policy = policyClass.newInstance();
		} catch (InstantiationException e) {
			return;
		} catch (IllegalAccessException e) {
			return;
		}
		if(o != null)
		{
			objectPolicies.put(o, policy);
		}
		if (parent != null)
		{
			if (parentMap.containsKey(parent))
			{
				parentMap.get(parent).add(o);
			}
			else
			{
				LinkedList<Object> list = new LinkedList<Object>();
				list.add(o);
				parentMap.put(parent, list);
			}
		}
	}
	public static void addObjectPolicy(Object o)
	{
		//System.err.println("Adding object policy " + o.getClass());
		PolicyType classPolicy;
		if(o != null)
		{
			classPolicy = lookupClassPolicy(o.getClass());
		}
		else
		{
			classPolicy = null;
		}
		if (classPolicy != null)
		{
			classPolicy = classPolicy.generateOrigin();
			//AbstractPolicy objectPolicy = classPolicy.generatePolicy(o);
			if (objectPolicies == null)
			{
				objectPolicies = new WeakIdentityHashMap<Object, PolicyType>();
			}
			objectPolicies.put(o, classPolicy);
		}
	}

	public static PolicyType lookupClassPolicy(Class<?> clazz)
	{
		//System.err.println("1Looking up " + clazz.getName());
		//new Exception().printStackTrace();
		if (classPolicies == null)
		{
			classPolicies = new HashMap<String, PolicyType>();
		}
		return classPolicies.get(clazz.getName());
	}

	public static PolicyType lookupObjectPolicy(Object o)
	{
		if(o == null)
			return null;
		if (objectPolicies == null)
		{
			objectPolicies = new WeakIdentityHashMap<Object, PolicyType>();
		}
		PolicyType objectPolicy = objectPolicies.get(o);
		if (objectPolicy != null)
		{
			return objectPolicy;
		}
		objectPolicy = lookupClassPolicy(o.getClass());
		return objectPolicy;
	}
	public static void setObjectPolicy(Object self,
			PolicyType classPolicy) {
		if (objectPolicies == null)
		{
			objectPolicies = new WeakIdentityHashMap<Object, PolicyType>();
		}
		objectPolicies.put(self, classPolicy);		
	}
	public static HashMap<Object, PolicyType> lookupParentPolicy(Object parent) {
		if (parentMap == null) {
			parentMap = new HashMap<Object, LinkedList<Object>>();
		}
		HashMap<Object, PolicyType> ans = new HashMap<Object, PolicyType>();
		if (parentMap.containsKey(parent)) {
			for (Object obj : parentMap.get(parent)) {
				ans.put(obj, lookupObjectPolicy(obj));
			}
		}
		return ans;
	}
}
